`timescale 1ns/1ps
// -----------------------------------------------------------------------------
// Copyright (c) 2014-2023 All rights reserved
// *********************************************************************************
// Project Name : 
// Author       : Dark
// Create Time  : 2023-01-14 10:13:22
// Revise Time	: 2023-01-14 10:13:22
// File Name    : pc.sv
// Abstract     : 
`include "defines.svh"
module pc_gen (
	input	logic			clk,    // Clock
	input	logic			rst_n,  // Synchronous reset active low

	input	logic	[ 3:0]	branch,
	input	logic			zero,    	//Branch jump
	input	logic			less,		//Branch jump	
	input	logic	[31:0]	imm,		//Branch jump
	input	logic	[31:0]	rs1_data,	//Branch jump
	input 	logic	[31:0]	PC_id2ex,	//Branch jump
	input 	logic	[31:0]	PC,			//PC for +4

	input   logic   [ 4:0]  rs1_if2id,
    input   logic   [ 4:0]  rs2_if2id,
    input   logic   [ 4:0]  rd_id2ex,
    input   logic           mem_rd_id2ex,
    
    output  logic           refetch_flag,//nop the pipeline 
	output 	logic			PCjump_flag, 
	output 	logic			PCjump_flag_pipe, 	//to if2id
	output 	logic	[31:0]	nextPC  	//to irom address	
);


//=================================================================================
// Signal declaration
//=================================================================================
	logic			PCS_imm;
	logic	[31:0]	pc_base;	
	logic	[31:0]	pc_offset;	
//=================================================================================
// Body
//=================================================================================
	assign 	PCS_imm			=	  (branch == `BRAN_JAL)
								||(branch == `BRAN_JALR)
								||(branch == `BRAN_BEQ && zero == 1'b1)
								||(branch == `BRAN_BNE && zero == 1'b0)
								||((branch == `BRAN_BLT||branch == `BRAN_BLTU)&& less == 1'b1)
								||((branch == `BRAN_BGE||branch == `BRAN_BGEU)&& less == 1'b0);
	assign	PCjump_flag 	= PCS_imm&(~PCjump_flag_pipe);//Disable next 
    assign  refetch_flag  	= mem_rd_id2ex				// Load Type
                            &&(rd_id2ex == rs1_if2id||rd_id2ex == rs2_if2id); 

// // pc source select
// 	always_comb begin
// 		casez (branch)  
// 			`BRAN_NOJ	:PCAsrc = `A_4BYTE;
// 			`BRAN_JAL	:PCAsrc = `A_IMM;
// 			`BRAN_JALR	:PCAsrc = `A_IMM;
// 			`BRAN_BEQ	:PCAsrc = (zero == 1'b1)?`A_IMM:`A_4BYTE;
// 			`BRAN_BNE	:PCAsrc = (zero == 1'b0)?`A_IMM:`A_4BYTE;
// 			`BRAN_BLT	:PCAsrc = (less == 1'b1)?`A_IMM:`A_4BYTE;
// 			`BRAN_BGE	:PCAsrc = (less == 1'b0)?`A_IMM:`A_4BYTE;	
// 			default 	:PCAsrc = `A_4BYTE;/* default */
// 		endcase
// 	end
//	if == right has x ,	result =x

	/* !!! need diff PC and PC_id2ex !!!*/
	always_comb	begin
		if (branch == `BRAN_JALR)
			pc_base	<=	rs1_data;
		else if (PCjump_flag)
			pc_base	<=	PC_id2ex;
		else
			pc_base	<=	PC;
	end
	assign	pc_offset = PCjump_flag? imm : 32'd4 ;
	//  delayed by one cycle 
	always_ff @(posedge clk) begin 
		if(~rst_n) 
			PCjump_flag_pipe  	<= 1'b0;
		else 
			PCjump_flag_pipe	<= PCjump_flag;
	end
// pc generate
//	assign 	nextPC 		= pc_base	+	pc_offset;

	assign 	nextPC 	= 	PCjump_flag?			imm + PC_id2ex: 
						(branch == `BRAN_JALR)?	rs1_data + 32'd4: 
						PC + 32'd4;	
endmodule 



